package com.tgram.android_mapapi.map;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.client.ClientProtocolException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.esri.android.map.TiledServiceLayer;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.SpatialReference;
import com.tgram.android_mapapi.Util.DirManager;
import com.tgram.android_mapapi.Util.UtilNum;
/**
 * 
 * @classname ArcgisWebTileLayer.java
 * @description 用于加载网络瓦片图
 */
public class ArcgisWebTileLayer extends TiledServiceLayer {

	private String filename = "test.xml";
	private static String CACHE_MAP = DirManager.DIR_MAP_CACHE + "Tiled";// 地图缓存地址
	private TileInfo tile;// 瓦片信息
	private SpatialReference spatialReference;// 空间参考系
	private Envelope fullExtent;
	private Envelope initialExtent;
	private String urlPattern;

	private int _offset_x = 0;
	private int _offset_y = 0;
	private int[] levelArr;

	/**
	 * 构造函数，获取xml数据
	 * 
	 * @param url
	 */
	public ArcgisWebTileLayer(final String url) {
		super(url);
	{
	CACHE_MAP = DirManager.DIR_MAP_CACHE + "HangZhou";
		}
		new Thread() {
			@Override
			public void run() {
				try {
					getURLContent(url, "utf-8");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}.start();
	}

	private void getURLContent(String url, String encoding) throws IOException {
		StringBuffer content = new StringBuffer();
		InputStream in = null;
		FileWriter fw = null;
		try {
			URL u = new URL(url);
			in = new BufferedInputStream(u.openStream());
			InputStreamReader theHTML = new InputStreamReader(in, encoding);
			int c;
			while ((c = theHTML.read()) != -1) {
				content.append((char) c);
			}
			File file = new File(DirManager.DIR_DOWNLOAD + filename);
			if (!file.exists()) {
				file.createNewFile();
			}
			fw = new FileWriter(DirManager.DIR_DOWNLOAD + filename);
			fw.write(content.toString().replace("&", "&amp;"));
			fw.flush();
			fw.close();
		}
		// 处理异常
		catch (MalformedURLException e) {
			System.err.println(e);
		} catch (IOException e) {
			System.err.println(e);
		} finally {
			if (in != null) {
				in.close();
			}
			if (fw != null) {
				fw.close();
			}
		}
		Message msg = new Message();
		Bundle bundle = new Bundle();
		bundle.putString("path", DirManager.DIR_DOWNLOAD + filename);
		msg.setData(bundle);
		mHander.sendMessage(msg);
	}

	/**
	 * 解析xml
	 * 
	 * @param path
	 *            文件路径
	 * @throws ParserConfigurationException
	 */
	private void init(String path) throws ParserConfigurationException {
		File file = new File(path);
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
				.newInstance();
		final DocumentBuilder docBuilder = docBuilderFactory
				.newDocumentBuilder();
		Document doc = null;
		try {
			doc = docBuilder.parse(file);
			
			Element elemFull = (Element) doc.getElementsByTagName(
					ConstantsSetting.MAP_KEY_FULLEXTENT).item(0);
			fullExtent = new Envelope(Double.parseDouble(elemFull
					.getElementsByTagName(ConstantsSetting.MAP_KEY_XMIN).item(0)
					.getFirstChild().getNodeValue()), Double.parseDouble(elemFull
					.getElementsByTagName(ConstantsSetting.MAP_KEY_YMIN).item(0)
					.getFirstChild().getNodeValue()), Double.parseDouble(elemFull
					.getElementsByTagName(ConstantsSetting.MAP_KEY_XMAX).item(0)
					.getFirstChild().getNodeValue()), Double.parseDouble(elemFull
					.getElementsByTagName(ConstantsSetting.MAP_KEY_YMAX).item(0)
					.getFirstChild().getNodeValue()));
			initialExtent = fullExtent;
			urlPattern = doc
					.getElementsByTagName(ConstantsSetting.MAP_KEY_URLPATTERN)
					.item(0).getFirstChild().getNodeValue();
			urlPattern = urlPattern.replace(ConstantsSetting.MAP_HOST,
					ConstantsSetting.MAP_HOST_REFLECT);
			Element tileInfo = (Element) doc.getElementsByTagName(
					ConstantsSetting.MAP_KEY_TILEINFO).item(0);
			int dpi = Integer.parseInt(tileInfo
					.getElementsByTagName(ConstantsSetting.MAP_KEY_DPI).item(0)
					.getFirstChild().getNodeValue());
			int tileWidth = Integer.parseInt(tileInfo
					.getElementsByTagName(ConstantsSetting.MAP_KEY_WIDTH).item(0)
					.getFirstChild().getNodeValue());
			int tileHeight = Integer.parseInt(tileInfo
					.getElementsByTagName(ConstantsSetting.MAP_KEY_HEIGHT).item(0)
					.getFirstChild().getNodeValue());
			int wkid = Integer.parseInt(tileInfo
					.getElementsByTagName(ConstantsSetting.MAP_KEY_WKID).item(0)
					.getFirstChild().getNodeValue());
			spatialReference = SpatialReference.create(wkid);
			Element lodsList = (Element) tileInfo.getElementsByTagName(
					ConstantsSetting.MAP_KEY_LODS).item(0);
			NodeList pointList = tileInfo
					.getElementsByTagName(ConstantsSetting.MAP_KEY_ORIGIN);
			Element orgEle = (Element) pointList.item(0);
			double x = Double.parseDouble(orgEle
					.getElementsByTagName(ConstantsSetting.MAP_KEY_X).item(0)
					.getFirstChild().getNodeValue());
			double y = Double.parseDouble(orgEle
					.getElementsByTagName(ConstantsSetting.MAP_KEY_Y).item(0)
					.getFirstChild().getNodeValue());
			Point origin = new Point(x, y);
			NodeList lodList = lodsList
					.getElementsByTagName(ConstantsSetting.MAP_KEY_LOD);
			int levels = lodList.getLength();
			double[] scale = new double[levels];
			double[] res = new double[levels];
			levelArr = new int[levels];
			for (int i = 0; i < levels; i++) {
				Element e = (Element) lodList.item(i);
				scale[i] = Double.parseDouble(e
						.getElementsByTagName(ConstantsSetting.MAP_KEY_SCALE)
						.item(0).getFirstChild().getNodeValue());
				res[i] = Double.parseDouble(e
						.getElementsByTagName(ConstantsSetting.MAP_KEY_RESOLUTION)
						.item(0).getFirstChild().getNodeValue());
				levelArr[i] = Integer.parseInt(e
						.getElementsByTagName(ConstantsSetting.MAP_KEY_LEVEL)
						.item(0).getFirstChild().getNodeValue());
			}
			tile = new TileInfo(origin, scale, res, levels, dpi, tileWidth,
					tileHeight);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public TileInfo getTileInfo() {
		return tile;
	}

	@Override
	protected void initLayer() {
		if (getID() == 0) {
			this.nativeHandle = create();
		} else {
			setFullExtent(fullExtent);// 设置全服地图范围
			setInitialExtent(initialExtent);// 设置初始化地图范围
			setDefaultSpatialReference(spatialReference);// 设置空间参考
			setTileInfo(tile);// 设置tileInfo
			super.initLayer();
		}
	}

	@Override
	protected void requestTile(int level, int col, int row) {
		super.requestTile(level, col, row);
	}

	/**
	 * 读取对应瓦片图数据
	 */
	@Override
	protected byte[] getTile(int level, int row, int col) throws IOException {
		byte[] arrayOfByte = null;
		arrayOfByte = getOfflineCacheFile(level, col, row);
		if (null == arrayOfByte) {
			ByteArrayOutputStream bos = null;
			BufferedInputStream bis = null;
			HttpURLConnection httpUrl = null;
			try {
				String curUrl = urlPattern
						.replace("\\{0\\}",
								UtilNum.getFormatNum("" + levelArr[level], 2))
//								"" + levelArr[level])
						.replace(
								"\\{1\\}",
								UtilNum.getFormatNum(
										""
												+ Math.round(_offset_y
														/ tile.getResolutions()[level]
														/ tile.getTileHeight())
												+ col, 8))
						.replace(
								"\\{2\\}",
								UtilNum.getFormatNum(
										(""
												+ Math.round(_offset_x
														/ tile.getResolutions()[level]
														/ tile.getTileWidth()) + row),
										8));
				URL url = new URL(curUrl);
				httpUrl = (HttpURLConnection) url.openConnection();
				httpUrl.connect();
				bos = new ByteArrayOutputStream();
				bis = new BufferedInputStream(httpUrl.getInputStream());
				byte[] buf = new byte[1024];
				int bytes_read = 0;
				while ((bytes_read = bis.read(buf)) != -1) {
					bos.write(buf, 0, bytes_read);
				}
				arrayOfByte = bos.toByteArray();
				AddOfflineCacheFile(level, col, row, arrayOfByte);
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (bos != null) {
					bos.close();
				}
				if (bis != null) {
					bis.close();
				}
				if (httpUrl != null) {
					httpUrl.disconnect();
				}
			}
		}
		return arrayOfByte;
	}

	/**
	 * 将图片保存到本地
	 * 
	 * @param level
	 * @param col
	 * @param row
	 * @param bytes
	 * @return
	 */
	private byte[] AddOfflineCacheFile(int level, int col, int row, byte[] bytes) {

		File file = new File(CACHE_MAP);
		if (!file.exists()) {
			file.mkdirs();
		}
		File levelfile = new File(CACHE_MAP + File.separator + level);
		if (!levelfile.exists()) {
			levelfile.mkdirs();
		}
		File colfile = new File(CACHE_MAP + File.separator + level
				+ File.separator + col);
		if (!colfile.exists()) {
			colfile.mkdirs();
		}
		File rowfile = new File(CACHE_MAP + File.separator + level
				+ File.separator + col + File.separator + row + ".dat");
		if (!rowfile.exists()) {
			FileOutputStream out = null;
			try {
				out = new FileOutputStream(rowfile);
				out.write(bytes);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return bytes;

	}

	/**
	 * 获取本地图片
	 * 
	 * @param level
	 * @param col
	 * @param row
	 * @return
	 */
	private byte[] getOfflineCacheFile(int level, int col, int row) {
		byte[] bytes = null;
		File rowfile = new File(CACHE_MAP + File.separator + level
				+ File.separator + col + File.separator + row + ".dat");

		if (rowfile.exists()) {
			bytes = CopySdcardbytes(rowfile);
		} else {
			bytes = null;
		}
		return bytes;
	}

	/**
	 * 读取本地图片流
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	private byte[] CopySdcardbytes(File file) {
		byte[] bytes = null;
		FileInputStream in = null;
		ByteArrayOutputStream out = null;
		try {
			in = new FileInputStream(file);
			out = new ByteArrayOutputStream(1024);
			byte[] temp = new byte[1024];
			int size = 0;
			while ((size = in.read(temp)) != -1) {
				out.write(temp, 0, size);
			}
			bytes = out.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return bytes;
	}

	/**
	 * 下载完xml文件，返回主线程处理
	 */
	private Handler mHander = new Handler() {
		public void handleMessage(android.os.Message msg) {
			try {
				init(msg.getData().getString("path"));
				if (true) {// 是否初始化图层
					getServiceExecutor().submit(new Runnable() {
						@Override
						public void run() {
							initLayer();
						}
					});
				}
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			}
		};
	};

}
